<template>
  <!-- 实现弹窗 1. el-dialog  -->
  <el-dialog v-model="dialogVisible">
    <!-- 树组件数据展示 1. el-tree  -->
    <el-tree
      :data="treeData"
      show-checkbox
      :props="defaultProps"
      :default-expand-all="true"
      highlight-current
      ref="menuTree"
      node-key="id"
      :check-strictly="checkStrictly"
    />
    <!-- 树组件数据提交按钮 1. el-tree 数据提交按钮 全部选择 和 确认分配  -->
    <template #footer>
      <el-button type="primary" @click="handleCheckAll">全部选择</el-button>
      <el-button type="warning" @click="handleSubmit">确认分配</el-button>
    </template>
  </el-dialog>
</template>

<script lang="ts" setup>
import { IRole } from "@/api/role"
// 树组件数据展示 2. 导入 useMenuStore
import { useMenuStore } from "@/stores/menu"
import { PropType } from "vue"
import { ElTree } from "element-plus"
import Node from "element-plus/es/components/tree/src/model/node.mjs"
import { allocRoleAccess, getRoleAccess } from "@/api/roleAccess"
import { useReloadPage } from "@/hooks/useReloadPage"
// 树组件数据提交按钮 2. 先解除严格关系，true表示不关联，不然半选数据会导致 数据 子节点返显全选
const checkStrictly = ref(false)
const { reloadPage } = useReloadPage()
// 树组件数据展示 3. 使用 useMenuStore
const store = useMenuStore()
// 树组件数据展示 4. 拿到所有菜单数据，简化格式
const treeData = computed(() => store.state.menuTreeData)
// 树组件数据展示 5. 执行 useMenuStore 获取所有的菜单数据 函数
onMounted(() => {
  // 获取所有的菜单数据
  store.getAllMenuList()
})
// 树组件数据展示 6. 定义 el-tree 的 节点 信息，不定义会报错
const defaultProps = {
  children: "children",
  label: "title"
}
// 树组件数据提交按钮 3. 组件 ts 类型
type ElTreeInstance = InstanceType<typeof ElTree>
// 树组件数据提交按钮 4. 获取 el-tree 的组件实例， 使用上方 ts 类型
const menuTree = ref<ElTreeInstance | null>(null)
// 树组件数据提交按钮 5. 是否全选状态控制变量
const isCheckAll = ref(false)
// 树组件数据提交按钮 6. 实现 全部选择 函数
const handleCheckAll = () => {
  // if (!isCheckAll.value) {
  //   // setCheckedNodes 配合 node-key="id",才有效 ,false 代表不只选中子节点，父级也要选中
  //   menuTree.value?.setCheckedNodes(treeData.value as unknown as Node[], false)
  // } else {
  //   menuTree.value?.setCheckedNodes([], false)
  // }
  // isCheckAll.value = !isCheckAll.value
  // 6-1. 修改 checkStrictly 状态
  checkStrictly.value = false
  // 6-2. 是因为 check-strictly 从 true 直接改 false , 再去全选， 子节点选中状态用问题，用 setTimeout 异步改变选中状态，就没问题了
  setTimeout(() => {
    if (!isCheckAll.value) {
      menuTree.value?.setCheckedNodes(
        treeData.value as unknown as Node[],
        false
      )
    } else {
      menuTree.value?.setCheckedNodes([], false)
    }
    isCheckAll.value = !isCheckAll.value
  })
}
const { proxy } = getCurrentInstance()!
// 树组件数据提交按钮 7. 确认提交 函数
const handleSubmit = async () => {
  const tree = menuTree.value!
  // 	若节点可用被选中 (show-checkbox 为 true), 它将返回当前选中节点 key 的数组
  // 树组件数据提交按钮 7-1. 子级都被选中，全选的时候，父节点会是全选，父级也要拿到，tree.getCheckedKeys(false)  的 false,表示要包含父级节点
  const keys = tree.getCheckedKeys(false)
  // 若节点可被选中(show-checkbox 为 true)，则返回目前半选中的节点的 key 所组成的数组
  // 树组件数据提交按钮 7-2. 有一个子节点，被选中，父节点会是半选，父级也要拿到
  const halfKeys = tree.getHalfCheckedKeys()
  // 树组件数据提交按钮 7-3. 获取所有选中节点
  const selectKeys = [...keys, ...halfKeys]
  // 树组件数据提交按钮 7-4. 请求接口更新 角色对应的权限
  const res = await allocRoleAccess(role.id, selectKeys as number[])
  if (res.code === 0) {
    proxy?.$message.success("权限分配成功")
    // 树组件数据提交按钮 7-5. 接口请求成功，刷新页面
    reloadPage()
  }
}
// 实现弹窗 2. 定义 接受 prop
const { role, modelValue } = defineProps({
  role: {
    type: Object as PropType<IRole>,
    required: true
  },
  modelValue: {
    type: Boolean,
    default: false
  }
})

// 实现弹窗 3. 定义 el-dialog 控制变量 dialogVisible 接受 prop
const dialogVisible = ref(modelValue)

// 实现弹窗 4. 定义 update:modelValue 触发事件
const emit = defineEmits(["update:modelValue"])

// 实现弹窗 5. watch 监听 el-dialog 控制变量 dialogVisible 触发 update:modelValue 事件
watch(
  () => dialogVisible.value,
  (newValue) => {
    emit("update:modelValue", newValue)
  }
)
// 树组件数据返显 2. 组件加载 获取角色的 权限，返显 执行函数
const getRoleAccessList = async () => {
  // 树组件数据返显 2-1. 在显示复选框的情况下，是否严格的遵循父子不互相关联的做法，默认为 false
  // 这样就不会有，半选的父节点数据，再返显时导致所有子节点，都被选中
  checkStrictly.value = true
  // 树组件数据返显 2-2. 请求 角色 和 资源对应 关系的集合
  const res = await getRoleAccess(role.id)
  /*
    console.log(res) 打印结果

    [
      { id: 73, role_id: 2, access_id: 37 },
      { id: 74, role_id: 2, access_id: 34 },
      { id: 75, role_id: 2, access_id: 35 },
      { id: 76, role_id: 2, access_id: 36 },
      { id: 77, role_id: 2, access_id: 39 },
    ]
    */
  if (res.code === 0) {
    // 树组件数据返显 2-3. 生成 el-tree 选中数据的集合
    const access = res.data.map((item) => item.access_id)
    // 树组件数据返显 2-4. el-tree setCheckedKeys 设置 el-tree 选中状态
    menuTree.value?.setCheckedKeys(access)
    // 树组件数据返显 2-5 返显完毕后 使用 setTimeout 把checkStrictly 设为 false,避免数据返显问题 ，nexticket 没效果
      checkStrictly.value = false
    }, 0)
  }
  //
}
// 树组件数据返显 1. 组件加载 获取角色的 权限
onMounted(() => {
  console.log("----")
  getRoleAccessList()
})
</script>
